package org.spark.api.util;

import org.msgpack.core.MessageBufferPacker;
import org.msgpack.core.MessagePack;

import java.io.IOException;
import java.time.ZonedDateTime;

/**
 * 序列化msgpack
 * 支持int、long、boolean、short、float、double，以及它们对应的包装类型，支持String和byte[]
 * NOT thread safe
 * 用完需要关闭
 * Created by smyang on 16/6/1.
 */
public class MsgPackWriter extends MessageBufferPacker {

    private static final byte[] zeroBytes = new byte[0];

    public MsgPackWriter() {
        super(MessagePack.DEFAULT_PACKER_CONFIG);
    }

    public static MsgPackWriter create() {
        return new MsgPackWriter();
    }

    public MsgPackWriter pack(Object s) throws IOException {
        if (s == null) {
            return this;
        }

        if (s instanceof Integer) {
            super.packInt((Integer) s);
        } else if (s instanceof Long) {
            super.packLong((Long) s);
        } else if (s instanceof Boolean) {
            super.packBoolean((Boolean) s);
        } else if (s instanceof Short) {
            super.packShort((Short) s);
        } else if (s instanceof Float) {
            super.packFloat((Float) s);
        } else if (s instanceof Double) {
            super.packDouble((Double) s);
        } else if (s instanceof String) {
            super.packString((String) s);
        } else if (s instanceof byte[]) {
            addByteArray((byte[]) s);
        } else {
            throw new IOException("Can NOT pack the class " + s.getClass().getCanonicalName());
        }

        return this;
    }

    public MsgPackWriter pack(int s) throws IOException {
        super.packInt(s);
        return this;
    }

    public MsgPackWriter pack(long s) throws IOException {
        super.packLong(s);
        return this;
    }

    public MsgPackWriter pack(short s) throws IOException {
        super.packShort(s);
        return this;
    }

    public MsgPackWriter pack(float s) throws IOException {
        super.packFloat(s);
        return this;
    }

    public MsgPackWriter pack(double s) throws IOException {
        super.packDouble(s);
        return this;
    }

    public MsgPackWriter pack(boolean s) throws IOException {
        super.packBoolean(s);
        return this;
    }

    public byte[] from(boolean s) throws IOException {
        clear();
        super.packBoolean(s);
        return toByteArray();
    }

    public byte[] from(int s) throws IOException {
        clear();
        super.packInt(s);
        return toByteArray();
    }

    public byte[] from(long s) throws IOException {
        clear();
        super.packLong(s);
        return toByteArray();
    }

    public byte[] from(short s) throws IOException {
        clear();
        super.packShort(s);
        return toByteArray();
    }

    public byte[] from(float s) throws IOException {
        clear();
        super.packFloat(s);
        return toByteArray();
    }

    public byte[] from(double s) throws IOException {
        clear();
        super.packDouble(s);
        return toByteArray();
    }

    /**
     * 这一个方法是特别注释掉的
     * 如果byte[]由单个String构成，请用s.getBytes()
     * 如果byte[]由多个数据段组成，请用from(Object...)
     * public byte[] from(String s) {
     * return s.getBytes();
     * }
     */

    public byte[] from(Object... objects) throws IOException {
        clear();
        for (Object object : objects) {
            pack(object);
        }

        return toByteArray();
    }

    /**
     * 清空已经打包在缓存内的数据，重置为初始化状态，准备打包新的数据
     *
     * @return this
     */
    public MsgPackWriter reset() {
        super.clear();
        return this;
    }

    @Override
    public MsgPackWriter packBoolean(boolean s) throws IOException {
        super.packBoolean(s);
        return this;
    }

    @Override
    public MsgPackWriter packInt(int s) throws IOException {
        super.packInt(s);
        return this;
    }

    @Override
    public MsgPackWriter packLong(long s) throws IOException {
        super.packLong(s);
        return this;
    }

    @Override
    public MsgPackWriter packShort(short s) throws IOException {
        super.packShort(s);
        return this;
    }

    @Override
    public MsgPackWriter packFloat(float s) throws IOException {
        super.packFloat(s);
        return this;
    }

    @Override
    public MsgPackWriter packDouble(double s) throws IOException {
        super.packDouble(s);
        return this;
    }

    @Override
    public MsgPackWriter packString(String s) throws IOException {
        super.packString(s);
        return this;
    }

    /**
     * 把byte[]打包进来
     * 注意src的内容会被复制，所以调用之后，src可以被修改
     *
     * @param src 被打包的内容
     * @return this
     * @throws IOException {@link org.msgpack.core.MessagePacker}的相应方法
     */
    public MsgPackWriter writeByteArray(byte[] src) throws IOException {
        if (src == null) {
            return writeByteArray(zeroBytes);
        } else {
            packBinaryHeader(src.length).writePayload(src);
            return this;
        }
    }

    /**
     * 把byte[]打包进来，性能比writeByteArray好一点
     * 注意src的内容不会被复制，所以需要保证，调用之后，src不被修改
     *
     * @param src 被打包的内容
     * @return this
     * @throws IOException {@link org.msgpack.core.MessagePacker}的相应方法
     */
    public MsgPackWriter addByteArray(byte[] src) throws IOException {
        if (src == null) {
            return writeByteArray(zeroBytes);
        } else {
            packBinaryHeader(src.length).addPayload(src);
            return this;
        }
    }

    public static void main(String[] args) throws IOException {
        test3();

        System.out.println("over");
    }

    static void test2() throws IOException {
        MsgPackWriter writer = MsgPackWriter.create();
        int a = 1;
        long b = 2L;
        String c = "aa";
        byte[] s = "bb".getBytes();
        writer.from(b, c, s);
        byte[] result = writer.toByteArray();
        writer.close();

        MsgPackReader reader = MsgPackReader.create(result);
        long bb = reader.unpackLong();
        String cc = reader.unpackString();
        byte[] ss = reader.unpackByteArray();

        reader.close();
    }

    static void test1() throws IOException {
        MsgPackWriter writer = MsgPackWriter.create();
        writer.reset();
//        writer.packMapHeader(0);
        writer.packInt(1);
//        byte[] empty = writer.toByteArray();
        writer.reset();
        writer.pack("cn");
        byte[] b1 = writer.toByteArray();

        MsgPackReader reader = MsgPackReader.create();
//        reader.reset(empty);
//        int a = reader.unpackMapHeader();
        String s = reader.reset(b1).unpackString();
        int z = 1;
    }

    static void test3() throws IOException {
        MsgPackWriter writer = MsgPackWriter.create();
        String s = "20200310";
        long timestamp = ZonedDateTime.now().toEpochSecond();
        long time = 20200310;
        byte[] b1 = writer.reset().pack(s).toByteArray();
        byte[] b2 = writer.reset().pack(timestamp).toByteArray();
        byte[] b3 = writer.reset().pack(time).toByteArray();
        int z = 1;
    }
}
